/*
 * @Author: zhouwei wei.zhou@flip.fun
 * @Date: 2024-04-26 15:28:58
 * @LastEditors: zhouwei wei.zhou@flip.fun
 * @LastEditTime: 2024-04-27 15:46:44
 * @FilePath: /redux/src/redux/index.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
/**
 *
 * @param {*} reducer  reducer函数
 * @param {*} applyMiddleware 中间件
 * @returns {{getState:()=>{},subscribe:()=>{},dispatch:()=>{}}} 返回一个对象
 * getState() 获取状态
 * subscribe() 订阅状态变化
 * dispatch() 触发状态变化
 */

export function createStore(reducer, applyMiddleware) {
  // applyMiddleware 是中间件函数
  // 如果是函数,则执行中间件函数,返回一个新的createStore函数
  // 然后执行新的createStore函数,返回一个store对象
  if (typeof applyMiddleware === "function") {
    const newCreateStore = applyMiddleware(createStore);
    const store = newCreateStore(reducer);
    return store;
  }
  // 状态
  let state;
  //  监听函数
  let listeners = [];
  //  获取状态的函数
  function getState() {
    return state;
  }
  //  触发状态变化的函数
  function dispatch(action) {
    // 重新执行reducer函数,返回新的状态
    state = reducer(state, action);
    // 通知所有的监听函数
    listeners.forEach((cb) => {
      cb();
    });
  }
  //  订阅函数
  function subscribe(cb) {
    listeners.push(cb);
  }
  //  初始化状态
  state = reducer(state, { type: "@/store_init" });
  return {
    getState,
    subscribe,
    dispatch,
  };
}

// reducers的{ key:reducer }
// 把{ key:reducer }组合成一个新的reducer函数, 通过便利reducers对象,执行每一个reducer函数,返回一个新的state对象
// 返回值是一个新的reducer函数
/**
 *
 * @param {{ key:reducer }} reducers
 * @returns
 */
export function combineReducers(reducers) {
  // 这里的state代表的是所有模块状态集合，action是当前的reducer调用的时候传入的参数
  const newReducer = (state = {}, action) => {
    return Object.keys(reducers).reduce((pre, key) => {
      const preState = state[key];
      const reducer = reducers[key];
      pre[key] = reducer(preState, action);
      return pre;
    }, {});
  };
  return newReducer;
}
export function logger({ getState }) {
  const next = (next) => {
    // 猜测 next其实好像就是dispatch
    const action = (action) => {
      // debugger
      // 在dispatch之前
      console.log("will dispatch1", action);

      const returnValue = next(action);

      // 在dispatch之后
      console.log("state after dispatch1", getState());

      // This will likely be the action itself, unless
      // a middleware further in chain changed it.
      return returnValue;
    };
    return action;
  };
  return next;
}
export function logger1({ getState }) {
  // 猜测 next其实好像就是dispatch

  const next1 = (next1) => {
    const action1 = (action1) => {
      // 在dispatch之前
      console.log("will dispatch2", action1);

      const returnValue = next1(action1);
      console.log(returnValue);
      // 在dispatch之后
      console.log("state after dispatch2", getState());

      // This will likely be the action itself, unless
      // a middleware further in chain changed it.
      return returnValue;
    };
    return action1;
  };
  return next1;
}
const compose =
  (...args) =>
  (param) => {
    /**
     * 执行流程
     * 第一次循环 , pre是dispatch , item是next1函数    next1(dispatch)返回值是函数action1
     * 第二次循环 , pre是action1 , item是next函数 , 返回值是next(action1)返回值是函数action
     * 结论返回值就是对所有中间件函数的返回值函数从右到左执行一次,  包装成执行栈, 依次把右边的函数传入到相邻左侧函数中,类似洋葱圈
     * 外面调用实际上就是最左边的先调用,然后把传入的回调函数执行,然后不断的把回调函数推入执行栈中进行执行,最后由内(最右边)到外(最左边)依此释放
     */
    return args.reduceRight((pre, item) => {
      // debugger
      return item(pre);
    }, param);
  };

/**
 *
 * @param {*} middleware
 * @returns
 */
export function applyMiddleware(...middleware) {
  // 返回值的函数提供给createStore调用
  return function enhancer(createStore) {
    return function newCreateStore(reducer) {
      const store = createStore(reducer);
      const getNewDispatchList = middleware.map((item) => item(store));
      //  getNewDispatchList 是先把中间件执行一次,拿到中间件的返回值
      console.log(
        getNewDispatchList,
        "getNewDispatchListgetNewDispatchListgetNewDispatchList"
      );
      // newDispatchFn  把所有的中间件通过compose包装起来
      const newDispatchFn = compose(...getNewDispatchList);
      // 执行包装函数 => 中间件返回值函数列表, 从右到左执行
      const newDispatch = newDispatchFn(store.dispatch);
      // newDispatch  最后拿到的是中间件返回值函数的返回值函数action
      console.log(newDispatch);
      // const getNewDispatch = middleware(store)
      // const newDispatch = getNewDispatch(store.dispatch)
      return {
        ...store,
        dispatch: newDispatch,
      };
    };
  };
}
